//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

// TO DO //
// I'm contemplating getting rid of all of this in replace
// of using TypeID< T >::GetID(). Much simpler, and I can extend
// it to support querying whether the type is pointer, pod, reference, const, ect..


#ifndef RS_REFLECTION_TYPES_HPP
#define RS_REFLECTION_TYPES_HPP

#include "rs/Assert.hpp"
#include "rs/Portability.hpp"
#include "rs/MetaFacilities.hpp"
#include <vector>
#include <map>
#include <string>

namespace rs
{
    namespace reflection
    {   
        namespace TypeQualifiers
        {
            enum Enum
            {
                None,
                Const,
                Pointer,
                ConstPointer
            };
        }

        namespace Types
        {
            enum Enum
            {
                Unknown,
                Void,
                Boolean,
                Int8,
                Int16,
                Int32,
                Int64,
                UInt8,
                UInt16,
                UInt32,
                UInt64,                
                Float,
                Double,
                Object,
                Vector,
                Map,
                String
            };
        }   
        
        inline UInt64 GetIntegral(
            Types::Enum type, TypeQualifiers::Enum qualifier = TypeQualifiers::None,
            Types::Enum templatedType = Types::Unknown, TypeQualifiers::Enum templatedQualifier = TypeQualifiers::None,
            Types::Enum secondaryElementType = Types::Unknown, TypeQualifiers::Enum secondaryElementQualifier = TypeQualifiers::None
        ) {
            return static_cast< UInt64 >(type & 0xff) | (static_cast< UInt64 >(qualifier & 0xff) << 8) | (static_cast< UInt64 >(templatedType & 0xff) << 16) | (static_cast< UInt64 >(templatedQualifier & 0xff) << 24) | (static_cast< UInt64 >(secondaryElementType & 0xff) << 32) | (static_cast< UInt64 >(secondaryElementQualifier & 0xff) << 40);
        }
        
        inline Types::Enum ExtractType(UInt64 value) {
            return static_cast< Types::Enum >(value & 0xff);
        }
        
        inline TypeQualifiers::Enum ExtractQualifier(UInt64 value) {
            return static_cast< TypeQualifiers::Enum >((value & 0xff00) >> 8);
        }
        
        template
        <
            Types::Enum type, TypeQualifiers::Enum qualifier = TypeQualifiers::None,
            Types::Enum templatedType = Types::Unknown, TypeQualifiers::Enum templatedQualifier = TypeQualifiers::None,
            Types::Enum secondaryElementType = Types::Unknown, TypeQualifiers::Enum secondaryElementQualifier = TypeQualifiers::None
        >
        struct StaticGetIntegral
        {
            static UInt64 const kValue = (type & 0xff) | ((qualifier & 0xff) << 8) | ((templatedType & 0xff) << 16) | ((templatedQualifier & 0xff) << 24) | (static_cast< UInt64 >(secondaryElementType & 0xff) << 32) | (static_cast< UInt64 >(secondaryElementQualifier & 0xff) << 40);
        };
        
        template< UInt64 value >
        struct StaticExtractType
        {
            static Types::Enum const kType = static_cast< Types::Enum >(value & 0xff);
        };
        
        template< UInt64 value >
        struct StaticExtractQualifier
        {
            static TypeQualifiers::Enum const kQualifier = static_cast< TypeQualifiers::Enum >((value & 0xff00) >> 8);
        };
        
        
        class Type
        {
        public: 
            
            Type()
            : qualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              type_(static_cast< UInt8 >(Types::Unknown)),
              templatedQualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              templatedType_(static_cast< UInt8 >(Types::Unknown)),
              secondaryElementQualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              secondaryElementType_(static_cast< UInt8 >(Types::Unknown)) {
            }
            
            Type(UInt64 value) {
                FromIntegral(value);
            }
            
            Type(Types::Enum type, TypeQualifiers::Enum qualifier = TypeQualifiers::None)
            : qualifier_(static_cast< UInt8 >(qualifier)),
              type_(static_cast< UInt8 >(type)),
              templatedQualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              templatedType_(static_cast< UInt8 >(Types::Unknown)),
              secondaryElementQualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              secondaryElementType_(static_cast< UInt8 >(Types::Unknown)) {  
            }
            
            Type(Types::Enum templatedType, TypeQualifiers::Enum templatedQualifier, Types::Enum elementType, TypeQualifiers::Enum elementQualifier)
            : qualifier_(static_cast< UInt8 >(elementQualifier)),
              type_(static_cast< UInt8 >(elementType)),
              templatedQualifier_(static_cast< UInt8 >(templatedQualifier)),
              templatedType_(static_cast< UInt8 >(templatedType)),
              secondaryElementQualifier_(static_cast< UInt8 >(TypeQualifiers::None)),
              secondaryElementType_(static_cast< UInt8 >(Types::Unknown)) {  
            }
            
            Type(Types::Enum templatedType, TypeQualifiers::Enum templatedQualifier, Types::Enum elementType, TypeQualifiers::Enum elementQualifier, Types::Enum secondaryElementType, TypeQualifiers::Enum secondaryElementQualifier)
            : qualifier_(static_cast< UInt8 >(elementQualifier)),
              type_(static_cast< UInt8 >(elementType)),
              templatedQualifier_(static_cast< UInt8 >(templatedQualifier)),
              templatedType_(static_cast< UInt8 >(templatedType)),
              secondaryElementQualifier_(static_cast< UInt8 >(secondaryElementQualifier)),
              secondaryElementType_(static_cast< UInt8 >(secondaryElementType)) {  
            }
            
            Type(Type const& other)
            : qualifier_(other.qualifier_),
              type_(other.type_),
              templatedQualifier_(other.templatedQualifier_),
              templatedType_(other.templatedType_),
              secondaryElementQualifier_(other.secondaryElementQualifier_),
              secondaryElementType_(other.secondaryElementType_) {
            }
            
            Boolean IsTemplated() const {
                return templatedType_ != Types::Unknown;
            }
            
            TypeQualifiers::Enum GetQualifier() const {
                return static_cast< TypeQualifiers::Enum >(templatedType_ != Types::Unknown ? templatedQualifier_ : qualifier_); 
            }
            
            Types::Enum GetType() const {
                return static_cast< Types::Enum >(templatedType_ != Types::Unknown ? templatedType_ : type_);
            }
            
            TypeQualifiers::Enum GetPrimaryQualifier() const {
                return static_cast< TypeQualifiers::Enum >(qualifier_); 
            }
            
            Types::Enum GetPrimaryType() const {
                return static_cast< Types::Enum >(type_);
            }
            
            
            TypeQualifiers::Enum GetElementQualifier() const {
                RS_ASSERT(static_cast< Types::Enum >(templatedType_) != Types::Unknown, "non-templated type");
                return static_cast< TypeQualifiers::Enum >(qualifier_);
            }
            
            Types::Enum GetElementType() const {
                RS_ASSERT(static_cast< Types::Enum >(templatedType_) != Types::Unknown, "non-templated type");
                return static_cast< Types::Enum >(type_);
            }
            
            TypeQualifiers::Enum GetSecondaryElementQualifer() const {
                RS_ASSERT(static_cast< Types::Enum >(secondaryElementType_) != Types::Unknown, "templated type does not contain a secondary element type");
                return static_cast< TypeQualifiers::Enum >(secondaryElementQualifier_);
            }
            
            Types::Enum GetSecondaryElementType() const {
                RS_ASSERT(static_cast< Types::Enum >(secondaryElementType_) != Types::Unknown, "templated type does not contain a secondary element type");
                return static_cast< Types::Enum >(secondaryElementType_);
            }
            
            UInt64 ToIntegral() const {
                return static_cast< UInt64 >(type_) | (static_cast< UInt64 >(qualifier_) << 8) | (static_cast< UInt64 >(templatedType_) << 16) | (static_cast< UInt64 >(templatedQualifier_) << 24) | (static_cast< UInt64 >(secondaryElementType_) << 32) | (static_cast< UInt64 >(secondaryElementQualifier_) << 40);
            }
            
            friend Boolean operator==(Type const& lhs, Type const& rhs) {
                return (
                    lhs.type_ == rhs.type_ &&
                    lhs.qualifier_ == rhs.qualifier_ &&
                    lhs.templatedType_ == rhs.templatedType_ &&
                    lhs.templatedQualifier_ == rhs.templatedQualifier_ &&
                    lhs.secondaryElementType_ == rhs.secondaryElementType_ &&
                    lhs.secondaryElementQualifier_ == rhs.secondaryElementQualifier_
                );
            }
            
            friend Boolean operator!=(Type const& lhs, Type const& rhs) {
                return !(lhs == rhs);
            }
            
        private:
            
            void FromIntegral(UInt64 value) {
            #if 0
                type_ = value & 0xff;
                qualifier_ = (value & 0xff00) >> 8;
                templatedType_ = (value & 0xff0000) >> 16;
                templatedQualifier_ = (value & 0xff000000) >> 24;
                secondaryElementType_ = (value & 0xff00000000LL) >> 32;
                secondaryElementQualifier_ = (value & 0xff0000000000LL) >> 40;
            #endif
                
                type_ = value & 0xff;
                qualifier_ = (value >> 8) & 0xff;
                templatedType_ = (value >> 16) & 0xff;
                templatedQualifier_ = (value >> 24) & 0xff;
                secondaryElementType_ = (value >> 32) & 0xff;
                secondaryElementQualifier_ = (value >> 40) & 0xff;
            }
            
        private:
            
            // qualifier_ and type_ act as the primary element type in the cass of templated types
            UInt8 qualifier_;
            UInt8 type_;
            UInt8 templatedQualifier_;
            UInt8 templatedType_;
            UInt8 secondaryElementQualifier_;
            UInt8 secondaryElementType_;
        };
        
        
        /////////////////////////////////
        // ConvertToQualifiedType //
        /////////////////////////////////
        
        template< typename T >
        struct ConvertToQualifiedType
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Unknown >::kValue;
        };
        
        template< typename T >
        struct ConvertToQualifiedType< T* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Unknown, TypeQualifiers::Pointer >::kValue;
        };
        
        template< typename T >
        struct ConvertToQualifiedType< T const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Unknown, TypeQualifiers::Const >::kValue;
        };
        
        template< typename T >
        struct ConvertToQualifiedType< T const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Unknown, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Void
        template< >
        struct ConvertToQualifiedType< void >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Void >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< void* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Void, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< void const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Void, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Boolean
        template< >
        struct ConvertToQualifiedType< Boolean >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Boolean >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Boolean* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Boolean, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Boolean const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Boolean, TypeQualifiers::Const >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Boolean const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Boolean, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Int8
        template< >
        struct ConvertToQualifiedType< Int8 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int8 >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int8* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int8, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int8 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int8, TypeQualifiers::Const >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int8 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int8, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Int16
        template< >
        struct ConvertToQualifiedType< Int16 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int16 >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int16* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int16, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int16 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int16, TypeQualifiers::Const >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int16 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int16, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Int32
        template< >
        struct ConvertToQualifiedType< Int32 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int32 >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int32* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int32, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int32 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int32, TypeQualifiers::Const >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int32 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int32, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Int64
        template< >
        struct ConvertToQualifiedType< Int64 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int64 >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int64* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int64, TypeQualifiers::Pointer >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int64 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int64, TypeQualifiers::Const >::kValue;
        };
        
        template< >
        struct ConvertToQualifiedType< Int64 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Int64, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // UInt8
        template< >
        struct ConvertToQualifiedType< UInt8 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt8 >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt8* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt8, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt8 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt8, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt8 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt8, TypeQualifiers::ConstPointer >::kValue;
        };

        // UInt16
        template< >
        struct ConvertToQualifiedType< UInt16 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt16 >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt16* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt16, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt16 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt16, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt16 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt16, TypeQualifiers::ConstPointer >::kValue;
        };

        // UInt32
        template< >
        struct ConvertToQualifiedType< UInt32 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt32 >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt32* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt32, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt32 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt32, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt32 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt32, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // UInt64
        template< >
        struct ConvertToQualifiedType< UInt64 >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt64 >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt64* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt64, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt64 const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt64, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< UInt64 const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::UInt64, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Float
        template< >
        struct ConvertToQualifiedType< Float >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Float >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Float* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Float, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Float const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Float, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Float const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Float, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Double
        template< >
        struct ConvertToQualifiedType< Double > 
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Double >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Double* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Double, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Double const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Double, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< Double const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::Double, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // String
        template< >
        struct ConvertToQualifiedType< std::string > 
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::String >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< std::string* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::String, TypeQualifiers::Pointer >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< std::string const >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::String, TypeQualifiers::Const >::kValue;
        };

        template< >
        struct ConvertToQualifiedType< std::string const* >
        {
            static UInt64 const kQualifiedType = StaticGetIntegral< Types::String, TypeQualifiers::ConstPointer >::kValue;
        };
        
        // Vector
        template< typename T >
        struct ConvertToQualifiedType< std::vector< T > > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Vector,
                    TypeQualifiers::None
                >::kValue;
        };

        template< typename T >
        struct ConvertToQualifiedType< std::vector< T >* > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Vector,
                    TypeQualifiers::Pointer
                >::kValue;
        };
        
        template< typename T >
        struct ConvertToQualifiedType< std::vector< T > const > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Vector,
                    TypeQualifiers::Const
                >::kValue;
        };

        template< typename T >
        struct ConvertToQualifiedType< std::vector< T > const* > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Vector,
                    TypeQualifiers::ConstPointer
                >::kValue;
        };
        
        // Map
        template< typename T, typename U >
        struct ConvertToQualifiedType< std::map< T, U > > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Map,
                    TypeQualifiers::None,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                >::kValue;
        };
        
        template< typename T, typename U >
        struct ConvertToQualifiedType< std::map< T, U >* > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Map,
                    TypeQualifiers::Pointer,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                >::kValue;
        };
        
        template< typename T, typename U >
        struct ConvertToQualifiedType< std::map< T, U > const > 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Map,
                    TypeQualifiers::Const,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                >::kValue;
        };
        
        template< typename T, typename U >
        struct ConvertToQualifiedType< std::map< T, U >  const*> 
        {
            static UInt64 const kQualifiedType =
                StaticGetIntegral
                <
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    Types::Map,
                    TypeQualifiers::ConstPointer,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                >::kValue;
        };
        
        template< typename T > UInt64 const ConvertToQualifiedType< T >::kQualifiedType;
        template< typename T > UInt64 const ConvertToQualifiedType< std::vector< T > >::kQualifiedType;
        template< typename T > UInt64 const ConvertToQualifiedType< std::vector< T > const >::kQualifiedType;
        template< typename T > UInt64 const ConvertToQualifiedType< std::vector< T >* >::kQualifiedType;
        template< typename T > UInt64 const ConvertToQualifiedType< std::vector< T > const* >::kQualifiedType;
        template< typename T, typename U > UInt64 const ConvertToQualifiedType< std::map< T, U > >::kQualifiedType;
        template< typename T, typename U > UInt64 const ConvertToQualifiedType< std::map< T, U > const >::kQualifiedType;
        template< typename T, typename U > UInt64 const ConvertToQualifiedType< std::map< T, U >* >::kQualifiedType;
        template< typename T, typename U > UInt64 const ConvertToQualifiedType< std::map< T, U > const* >::kQualifiedType;
        
        
        /////////////////////////////
        // ConvertToInstrinsicType //
        /////////////////////////////
        template< UInt64 value >
        struct ConvertToInstrinsicType {
            
        };
        
        // Unknown
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Unknown >::kValue >
        {
            typedef void* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Unknown, TypeQualifiers::Pointer >::kValue >
        {
            typedef void* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Unknown, TypeQualifiers::Const >::kValue >
        {
            typedef void const* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Unknown, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef void const* Type;
        };
        
        // Void
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Void >::kValue >
        {
            typedef void Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Void, TypeQualifiers::Pointer >::kValue >
        {
            typedef void* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Void, TypeQualifiers::Const >::kValue >
        {
            typedef void const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Void, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef void const* Type;
        };
        
        // Boolean
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean >::kValue >
        {
            typedef Boolean Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::Pointer >::kValue >
        {
            typedef Boolean* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::Const >::kValue >
        {
            typedef Boolean const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Boolean const* Type;
        };
        
        // Int8
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int8 >::kValue >
        {
            typedef Int8 Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::Pointer >::kValue >
        {
            typedef Int8* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::Const >::kValue >
        {
            typedef Int8 const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Int8 const* Type;
        };
        
        // Int16
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int16 >::kValue >
        {
            typedef Int16 Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::Pointer >::kValue >
        {
            typedef Int16* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::Const >::kValue >
        {
            typedef Int16 const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Int16 const* Type;
        };
        
        // Int32
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int32 >::kValue >
        {
            typedef Int32 Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::Pointer >::kValue >
        {
            typedef Int32* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::Const >::kValue >
        {
            typedef Int32 const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Int32 const* Type;
        };
        
        // Int64
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int64 >::kValue >
        {
            typedef Int64 Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::Pointer >::kValue >
        {
            typedef Int64* Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::Const >::kValue >
        {
            typedef Int64 const Type;
        };
        
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Int64 const* Type;
        };
        
        // UInt8
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8 >::kValue >
        {
            typedef UInt8 Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::Pointer >::kValue >
        {
            typedef UInt8* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::Const >::kValue >
        {
            typedef UInt8 const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef UInt8 const* Type;
        };

        // UInt16
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16 >::kValue >
        {
            typedef UInt16 Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::Pointer >::kValue >
        {
            typedef UInt16* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::Const >::kValue >
        {
            typedef UInt16 const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef UInt16 const* Type;
        };

        // UInt32
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32 >::kValue >
        {
            typedef UInt32 Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::Pointer >::kValue >
        {
            typedef UInt32* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::Const >::kValue >
        {
            typedef UInt32 const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef UInt32 const* Type;
        };
        
        // UInt64
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64 >::kValue >
        {
            typedef UInt64 Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::Pointer >::kValue >
        {
            typedef UInt64* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::Const >::kValue >
        {
            typedef UInt64 const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef UInt64 const* Type;
        };
        
        // Float
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Float >::kValue >
        {
            typedef Float Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::Pointer >::kValue >
        {
            typedef Float* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::Const >::kValue >
        {
            typedef Float const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Float const* Type;
        };
        
        // Double
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Double >::kValue >
        {
            typedef Double Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::Pointer >::kValue >
        {
            typedef Double* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::Const >::kValue >
        {
            typedef Double const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef Double const* Type;
        };
        
        // String
        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::String >::kValue >
        {
            typedef std::string Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::String, TypeQualifiers::Pointer >::kValue >
        {
            typedef std::string* Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::String, TypeQualifiers::Const >::kValue >
        {
            typedef std::string const Type;
        };

        template< >
        struct ConvertToInstrinsicType< StaticGetIntegral< Types::String, TypeQualifiers::ConstPointer >::kValue >
        {
            typedef std::string const* Type;
        };
        
        // Vector
        /*template< typename T >
        struct ConvertToInstrinsicType
        <
            StaticGetIntegral
            <
                StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                Types::Vector,
                TypeQualifiers::None
            >::kValue
        >
        {
            typedef std::vector< T > Type;
        };
        
        template< typename T >
        struct ConvertToInstrinsicType
        <
            StaticGetIntegral
            <
                StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                Types::Vector,
                TypeQualifiers::Const
            >::kValue
        >
        {
            typedef std::vector< T > const Type;
        };
        
        template< typename T >
        struct ConvertToInstrinsicType
        <
            StaticGetIntegral
            <
                StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                Types::Vector,
                TypeQualifiers::Pointer
            >::kValue
        >
        {
            typedef std::vector< T >* Type;
        };
        
        template< typename T >
        struct ConvertToInstrinsicType
        <
            StaticGetIntegral
            <
                StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                Types::Vector,
                TypeQualifiers::ConstPointer
            >::kValue
        >
        {
            typedef std::vector< T > const* Type;
        };*/

        
        template< typename T >
        struct TypeFactory
        {   
            static Type Create() {
                return Type(
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier
                );
            }
        };
        
        template< typename T >
        struct TypeFactory< std::vector< T > >
        {
            static Type Create() {
                return Type(
                    Types::Vector,
                    TypeQualifiers::None,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T >
        struct TypeFactory < std::vector< T > const >
        {
            static Type Create() {
                return Type(
                    Types::Vector,
                    TypeQualifiers::Const,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T >
        struct TypeFactory < std::vector< T >* >
        {
            static Type Create() {
                return Type(
                    Types::Vector,
                    TypeQualifiers::Pointer,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T >
        struct TypeFactory < std::vector< T > const* >
        {
            static Type Create() {
                return Type(
                    Types::Vector,
                    TypeQualifiers::ConstPointer,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T, typename U >
        struct TypeFactory < std::map< T, U > >
        {
            static Type Create() {
                return Type(
                    Types::Map,
                    TypeQualifiers::None,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T, typename U >
        struct TypeFactory < std::map< T, U > const >
        {
            static Type Create() {
                return Type(
                    Types::Map,
                    TypeQualifiers::Const,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T, typename U >
        struct TypeFactory < std::map< T, U >* >
        {
            static Type Create() {
                return Type(
                    Types::Map,
                    TypeQualifiers::Pointer,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        template< typename T, typename U >
        struct TypeFactory < std::map< T, U > const* >
        {
            static Type Create() {
                return Type(
                    Types::Map,
                    TypeQualifiers::ConstPointer,
                    StaticExtractType< ConvertToQualifiedType< T >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< T >::kQualifiedType >::kQualifier,
                    StaticExtractType< ConvertToQualifiedType< U >::kQualifiedType >::kType,
                    StaticExtractQualifier< ConvertToQualifiedType< U >::kQualifiedType >::kQualifier
                );
            } 
        };
        
        
        inline Boolean CompareArgumentTypes(UInt64 lhs, UInt64 rhs) {
            Type l(lhs), r(rhs);
            Boolean lhsPointer = (l.GetQualifier() == TypeQualifiers::Pointer) || (l.GetQualifier() == TypeQualifiers::ConstPointer);
            Boolean rhsPointer = (r.GetQualifier() == TypeQualifiers::Pointer) || (r.GetQualifier() == TypeQualifiers::ConstPointer);
            Boolean sameType = l.GetType() == r.GetType();
            Boolean sameElements = true;
            if (l.IsTemplated()) {
                sameElements =
                    (l.GetElementType() == r.GetElementType()) &&
                    (l.GetElementQualifier() == r.GetElementQualifier()) &&
                    (l.GetSecondaryElementType() == r.GetSecondaryElementType()) &&
                    (l.GetSecondaryElementQualifer() == r.GetSecondaryElementQualifer());
                
            }
            
            return (lhsPointer == rhsPointer) && sameType && sameElements;
        }
    }
}


#endif // RS_REFLECTION_TYPES_HPP
